package org.smartboot.flow.example;

import org.smartboot.flow.core.EngineContext;
import org.smartboot.flow.core.ExecutionListenerRegistry;
import org.smartboot.flow.core.ExecutionListenerSupport;
import org.smartboot.flow.core.Key;
import org.smartboot.flow.core.Measurable;
import org.smartboot.flow.core.metrics.Metrics;
import org.smartboot.flow.core.metrics.MetricsManager;
import org.smartboot.flow.core.metrics.NamedMetrics;
import org.springframework.beans.factory.InitializingBean;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author qinluo
 * @date 2023-01-09 18:50:47
 * @since 1.0.0
 */
public class MultipleBusinessMetricsListener extends ExecutionListenerSupport implements InitializingBean {

    @Override
    public void afterPropertiesSet() throws Exception {
        MetricsManager.setMetricsCreator(MultipleBusinessMetrics::new);
        ExecutionListenerRegistry.register(this);
    }

    @Override
    public <T, S> void beforeExecute(EngineContext<T, S> context, Object object) {
        if (!(object instanceof Measurable)) {
            return;
        }

        Measurable measurable = (Measurable) object;
        Metrics metrics = measurable.getMetrics();
        if (metrics.getClass() != MultipleBusinessMetrics.class) {
            return;
        }

        Map<Object, Long> escaped = context.getExt(Key.of(this));
        if (escaped == null) {
            escaped = new ConcurrentHashMap<>();
            context.putExt(Key.of(this), escaped);
        }

        String business = context.getExt(Key.of("business_key"));

        ((MultipleBusinessMetrics)metrics).addMetric(business, NamedMetrics.EXECUTE, 1);
        escaped.put(object, System.currentTimeMillis());
    }

    @Override
    public <T, S> void afterExecute(EngineContext<T, S> context, Object object) {
        if (!(object instanceof Measurable)) {
            return;
        }

        Measurable measurable = (Measurable) object;
        Metrics metrics = measurable.getMetrics();
        if (metrics.getClass() != MultipleBusinessMetrics.class) {
            return;
        }

        Map<Object, Long> escaped = context.getExt(Key.of(this));
        if (escaped == null) {
            return;
        }

        Long start = escaped.remove(object);
        if (start == null) {
            return;
        }

        String business = context.getExt(Key.of("business_key"));
        MultipleBusinessMetrics metrics1 = (MultipleBusinessMetrics) metrics;

        if (context.getFatal() != null) {
            metrics1.addMetric(business, NamedMetrics.FAIL, 1);
        }
        long now = System.currentTimeMillis();
        metrics1.addMetric(business, NamedMetrics.TOTAL_ESCAPE, (now - start));
        metrics1.addMetric(business, NamedMetrics.MAX_ESCAPE, (now - start));
    }
}
